package com.xikang.ice.client.pool;

import Ice.ObjectPrx;
import com.xikang.ice.client.exception.ProxyCastException;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

public  class PooledProxyHandler<P extends ObjectPrx, H extends P> implements InvocationHandler {

    private final CommunicatorPool pool;

    private final String adapterIdKey;

    private final Class<P> proxyClass;

    private final Class<H> helperClass;

    private final boolean checkedCast;

    private final String proxyCacheKey;


    public PooledProxyHandler(CommunicatorPool pool, String adapterIdKey,
                              Class<P> proxyClass, Class<H> helperClass, boolean checkedCast) {
        this.pool = pool;
        this.adapterIdKey = adapterIdKey;
        this.proxyClass = proxyClass;
        this.helperClass = helperClass;
        this.checkedCast = checkedCast;
        this.proxyCacheKey = String.format("%s-%s", adapterIdKey, proxyClass);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        CommunicatorWithProxies communicatorWithProxies = null;
        try {
            communicatorWithProxies = pool.borrowObject();
            CommunicatorWithProxies finalCommunicatorWithProxies = communicatorWithProxies;
            if (!communicatorWithProxies.getProxies().containsKey(proxyCacheKey)) {
                String proxyString = communicatorWithProxies.getUserProperties().get(adapterIdKey);
                if (proxyString == null) {
                    throw new IllegalStateException("proxy config not found for adapter: " + adapterIdKey);
                }
                proxyString = proxyClass.getSimpleName() + proxyString;
                ObjectPrx base = finalCommunicatorWithProxies.getCommunicator().stringToProxy(proxyString);
                communicatorWithProxies.getProxies().put(proxyCacheKey,
                        castToProxy(base, proxyClass, helperClass, checkedCast));
            }
            Object target = communicatorWithProxies.getProxies().get(proxyCacheKey);

            return method.invoke(target, args);
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        } finally {
            pool.returnObject(communicatorWithProxies);
        }
    }





    private P castToProxy(ObjectPrx base, Class<P> proxyClass, Class<H> helperClass, boolean checkedCast) {

        //短连接方式,验证后，连接不会主动断开，无法实现k8部署的负载均衡,它这个短连接意义，和我们的理解可能不一样
//		base.ice_connectionCached(false);
//		base.ice_endpointSelection(EndpointSelectionType.Random);

        String castMethodName = checkedCast ? "checkedCast" : "uncheckedCast";
        Method castMethod;
        Object prx;

        try {
            castMethod = helperClass.getMethod(castMethodName, ObjectPrx.class);
            prx = castMethod.invoke(null, base);
        } catch (Exception e) {
            throw new ProxyCastException(e);
        }

        return (P) prx;
    }

    public String getAdapterIdKey() {
        return adapterIdKey;
    }

    public String getProxyCacheKey() {
        return proxyCacheKey;
    }
}
